/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package heuristics;

/**
 *
 * @author ahmad
 */
import algos.Geometry;
import java.awt.*;
import java.awt.geom.*;
import java.util.ArrayList;
import java.util.Arrays;

import misc.FOV;

import org.omg.CORBA.INTERNAL;

public class AngularSweep extends CoverageHeuristic {

    public AngularSweep(String file) {
        super(file, 8);
        number_of_orientations = number_of_men;
        continuous = true;
    }

    public AngularSweep(ArrayList<Rectangle> obstacles,
            ArrayList<Point2D.Double> cameras, ArrayList<Point2D.Double> people,
            int number_of_orientations) {
        super(obstacles, cameras, people, number_of_orientations, true);
        number_of_orientations = number_of_men;

        continuous = true;
    }

    void sweep() {
        spotted = new boolean[number_of_cameras][number_of_zooms][number_of_men][number_of_men];
        double tolerance = 0.00f;
        for (int camInd = 0; camInd < number_of_cameras; camInd++) {
            for (int zoom = 0; zoom < number_of_zooms; zoom++) {
                for (int personId = 0; personId < number_of_men; personId++) {
                    if (!picks(camInd, personId)) {
                        continue;
                    }
                    double angle = Geometry.computeAngle(new double[]{cameras.get(camInd).x, cameras.get(camInd).y, 0},
                            new double[]{people.get(personId).x, people.get(personId).y, 0},
                            new double[]{640, cameras.get(camInd).y, 0});
                    if (cameras.get(camInd).y > people.get(personId).y) {
                        angle = 2 * Math.PI - angle;
                    }
//                    System.out.println("This is the Rotation Angle : " + zoomRanges0[zoom] + " , " + zoomRanges1[zoom]);
                    FOV isoVist = getAngleIsovist(camInd, angle, zoomRanges0[zoom], zoomRanges1[zoom]);
                    for (int pId = 0; pId < number_of_men; pId++) {
                        for (int i = -1; i < 2; i++) {
                            double xx = people.get(pId).x;
                            double yy = people.get(pId).y;
                            xx += i * tolerance;
                            yy += i * tolerance;
                            Point2D.Double p = new Point2D.Double(xx, yy);
                            if (picks(camInd, pId) && isoVist.contains(p)) {
                                spotted[camInd][zoom][personId][pId] = true;
//                                System.out.println("Camera # " + camInd + " Spotted Man Number# " + pId+" at Zoom#"+zoom);
                            }
                        }
                    }
                    spotted[camInd][zoom][personId][personId] = true;
//                    System.out.println("Camera # " + camInd + " Spotted Man Number# " + personId);
                }
            }
        }
    }

    public int[] reassign() {
        sweep();
        //==============================================================================
//        for (int i = 0; i < spotted.length; i++) {
//            System.out.println("Camera : " + i);
//            for (int l = 0; l < spotted[i].length; l++) {
//                System.out.println("ZOOM LEVEL: " + l);
//                for (int j = 0; j < spotted[i][l].length; j++) {
//                    for (int k = 0; k < spotted[i][l][j].length; k++) {
//                        System.out.print(spotted[i][l][j][k] + " , ");
//                    }
//                    System.out.println();
//                }
//            }
//        }
        //==============================================================================
        boolean[] used = new boolean[number_of_cameras];
        boolean[] covered = new boolean[number_of_men];
        assignment = new int[number_of_cameras];
        deltaPan = new double[number_of_cameras];
        diffCamera = new double[number_of_men][3];
        zoomAssignment = new int[number_of_cameras];
        IDs = new int[number_of_cameras];
        int greedyCoverage = 0;
        for (int i = 0; i < number_of_cameras; i++) {
            int bestCamInd = -1, bestOrient = -1, bestZoom = -1;
            double best = -1;
            for (int camInd = 0; camInd < number_of_cameras; camInd++) {
                if (used[camInd]) {
                    continue;
                }
                int bestCamOrient = -1, totalCam = 0, bestCamZoom = -1;
                double bestCam = -1;
                boolean taken[] = new boolean[number_of_men];
                Arrays.fill(taken, false);
                for (int zoom = 0; zoom < number_of_zooms; zoom++) {
                    for (int orient = 0; orient < number_of_orientations; orient++) {
                        double orientCov = 0;
                        for (int p = 0; p < number_of_men; p++) {
                            if (covered[p]) {
                                continue;
                            }
                            if (spotted[camInd][zoom][orient][p]) {
                                orientCov += calProjection(camInd, p, zoom) * calDeltaPan(camInd, p, orient)*calAngle();
//                                orientCov += calProjection(camInd, p, zoom) * calDeltaPan(camInd, p, orient);
//                                orientCov += calProjection(camInd, p, zoom);
//                                orientCov++;
                                if (!taken[p]) {
                                    totalCam++;
                                    taken[p] = true;
                                }
                            }
                        }

                        if (bestCam < orientCov) {
                            bestCam = orientCov;
                            bestCamOrient = orient;
                            bestCamZoom = zoom;
                        }
                    }
                    if (Double.compare(best, 1.0 * bestCam / totalCam) < 0) {
                        best = 1.0 * bestCam / totalCam;
                        bestOrient = bestCamOrient;
                        bestCamInd = camInd;
                        bestZoom = bestCamZoom;
                    }
                }
                used[bestCamInd] = true;
                assignment[bestCamInd] = bestOrient;
                deltaPan[bestCamInd] = Math.abs(number_of_orientations / 2 - bestOrient) * (360 / number_of_orientations);
                zoomAssignment[bestCamInd] = bestZoom;

                IDs[bestCamInd] = bestOrient;
                for (int p = 0; p < number_of_men; p++) {
                    if (spotted[bestCamInd][bestZoom][bestOrient][p]) {
                        if (!covered[p]) {
                            greedyCoverage++;
                        }
                        covered[p] = true;
                    }
                }
            }
        }
        return assignment;
    }

    @Override
    public String toString() {
        return "Angular Sweep";
    }

    public boolean[][][][] getSets() {
        return this.spotted;
    }

    public int[] getZooms() {
        return this.zoomAssignment;
    }
}
